package com.apobates.forum.nanus.core;

import com.apobates.forum.nanus.*;
import org.apache.commons.lang3.RandomStringUtils;
import org.apache.commons.lang3.StringUtils;
import javax.servlet.http.HttpServletRequest;
import java.sql.Timestamp;
import java.time.LocalDateTime;
import java.util.*;
import java.util.function.BiFunction;

/**
 * 抽像的存储方案
 * @author xiaofanku@live.cn
 * @since 20210827
 */
public abstract class AbstractNanusStorage implements NanusStorage {
    private final NanusConverter beanConverter;
    private final NanusStorageConfig storageConfig;
    private final NanusHashStrategy hashStrategy;
    public final static String NP="-";

    /**
     *
     * @param beanConverter 存储对象转换器
     * @param storageConfig 存储配置
     * @param hashStrategy 存储内容的散列策略
     */
    public AbstractNanusStorage(NanusConverter beanConverter, NanusStorageConfig storageConfig, NanusHashStrategy hashStrategy) {
        this.beanConverter = beanConverter;
        this.storageConfig = storageConfig;
        this.hashStrategy = hashStrategy;
    }

    public NanusConverter getBeanConverter() {
        return beanConverter;
    }

    public NanusStorageConfig getStorageConfig() {
        return storageConfig;
    }

    public NanusHashStrategy getHashStrategy() {
        return hashStrategy;
    }

    /**
     * 返回Unix stamp
     * @return
     */
    public static long getUnixStamp(){
        long unixTime = System.currentTimeMillis() / 1000L;
        return unixTime;
    }

    /**
     * 将指定的日期转成unix timestamp
     *
     * @param date 要求不为null,反之返回0
     * @return
     */
    public static long getUnixStamp(LocalDateTime date){
        if (null == date) {
            return 0L;
        }
        return Timestamp.valueOf(date).getTime() / 1000L;
    }

    /**
     * 将指定的unix timestamp转成util.LocalDateTime
     *
     * @param unixStamp 要求不为null,否则抛出NPE.unix 时间戳,例:1589316 时间戳是自 1970 年 1 月 1 日（00:00:00 GMT）以来的秒数。它也被称为 Unix 时间戳（Unix Timestamp）。
     * @return
     */
    public static LocalDateTime getDateTimeByUnixStamp(long unixStamp) {
        if(0==unixStamp){
            return LocalDateTime.now();
        }
        return new Timestamp(unixStamp * 1000L).toLocalDateTime();
    }

    /**
     * 返回存储载荷使用的盐，若请求中包含token则使用不存在使用随机参数
     * @param request
     * @return
     */
    protected String getFactor(HttpServletRequest request){
        String token = request.getParameter("token");
        if(!StringUtils.isNotBlank(token)){
            token = RandomStringUtils.randomAlphanumeric(8);
        }
        return token;
    }

    /**
     * 无协议部分
     * @return
     */
    protected String getCookieDomain() throws IllegalArgumentException{
        Objects.requireNonNull(getStorageConfig());
        String d = getStorageConfig().getDomain();
        try {
            return d.substring(d.indexOf("://")+3);
        }catch (Exception e){
            throw new IllegalArgumentException("[Nanus]Domain names are not available in the configuration");
        }
    }


    protected String encode(String value, String defaultValue) {
        return getHashStrategy().encode(value, defaultValue);
    }

    protected String decode(String value, String defaultValue) {
        return getHashStrategy().decode(value, defaultValue);
    }

    /**
     * 抽像出getInstance和refresh共用的代码段
     * @param request
     * @return
     */
    protected abstract Optional<NanusStoragePayload> parsePayload(HttpServletRequest request);

    /**
     * 抽像出getInstance和refresh共用的代码段
     * @param nsp
     * @return
     */
    protected abstract Map<String,String> toPayloadMap(NanusStoragePayload nsp);

    /**
     * 合并存储对象的map结构
     * @param currentPayloadMap 当前存储的map
     * @param newBean
     * @return
     */
    protected Map<String,String> mergeBeanMap(Map<String, String> currentPayloadMap, NanusBean newBean){
        if(null == currentPayloadMap || currentPayloadMap.isEmpty()){
            return Collections.emptyMap();
        }
        //当前存储的map
        Map<String,String> newMap = getBeanConverter().toMap(newBean);
        //合并两个map
        return mergeMap(currentPayloadMap, newMap, (oldValue, newValue)-> newValue);
    }

    public static void main(String[] args) {
        Map<String,String> cur = new HashMap<>();
        cur.put("role", "admin");
        cur.put("uid", "1");
        cur.put("names", "xiaofanku");

        Map<String,String> nMap = new HashMap<>();
        nMap.put("role", "guest");
        nMap.put("uid", "1");
        nMap.put("names", "xiaofanku");
        nMap.put("avatar", "//x1.png");
        cur = mergeMap(cur, nMap, (oldValue, newValue)-> newValue);
        cur.entrySet().stream().forEach(entry->{
            System.out.println("{key:"+entry.getKey()+",val:"+entry.getValue()+"}");
        });
    }
    /**
     * 合并集合
     *
     * @param <K>
     * @param <V>
     * @param baseMap 以此集合为基准
     * @param extMap 在基准的集合上合并此集合
     * @param remappingFunction 合并时的运作函数
     * @return
     */
    public static <K,V> Map<K,V> mergeMap(Map<K,V> baseMap, Map<K,V> extMap, BiFunction<? super V, ? super V, ? extends V> remappingFunction){
        if(null == extMap || extMap.isEmpty()){
            return baseMap;
        }
        Map<K, V> data = new HashMap<>(baseMap);
        extMap.forEach((newKey, newVal)->{
            data.merge(newKey, newVal, remappingFunction);
        });
        return data;
    }
}
